import time,sys,json
from math import isnan
from ctp.OrderClass import OpenOrder,CloseOrder,OrderStatus,LogicOpratorStr
from ctp.thosttraderapi import THOST_FTDC_D_Buy,THOST_FTDC_D_Sell,THOST_FTDC_OF_Open,THOST_FTDC_OF_Close,THOST_FTDC_OF_CloseToday
from ctp.ctpApi import CTPapi,orderfield
from mainWindow_ui import Ui_MainWindow
from threading import Thread
from info import user_info,getCode,logicalOprator
from TQapi import TQapi
from tqsdk import TqAuth
from winsound import Beep
from PyQt5.QtWidgets import QMainWindow, QApplication,QTableWidgetItem,QPushButton#,QHeaderView,QPushButton,QWidget,QAbstractItemView
from PyQt5.QtCore import Qt,QObject,pyqtSignal,QEvent#,QStringListModel,QTextStream,pyqtSignal,QSize
from PyQt5.QtGui import QIcon,QFont,QColor
#读取合约列表
with open('InstrumentIDList.json','r',encoding='utf8') as f:
    InstrumentDict=json.load(f)
class SignalHandle(QObject):
    '''信号总线，要继承QObject signal的定义必须在init函数之外'''
    closeApiSignal=pyqtSignal(str)  #关闭线程
    getQuoteSignal=pyqtSignal(str)  #订阅品种
    updateGUISignal=pyqtSignal() #刷新界面的数据
    sendOrderSignal=pyqtSignal(OpenOrder) #提交预埋单
class MainWindow(QMainWindow,Ui_MainWindow):
    def __init__(self,InstrumentDict,signalHandle,user_info,tqApi,CTPapi,orderfield=orderfield) -> None:
        super().__init__()   #QMainWindow的初始化
        self.setupUi(self)   #把Qmainwindow放进UI类，作为背景窗口，然后添加控件
        self.InstrumentDict=InstrumentDict
        self.signalHandle=signalHandle
        self.user_info=user_info
        self.tqApi,self.CTPapi,self.orderfield=tqApi,CTPapi,orderfield
        #天勤量化线程
        Thread(target=self.tqApi.run).start()
        #CTP接口
        Thread(target=self.Join).start()

        self.comboBox.installEventFilter(self)
        # self.tqApiThread.start()
        self.currentID=None
        self.quoteDict={}
        with open('orderDict.json','r',encoding='utf8') as f:
            self.OrderDict=json.load(f)
            self.comboBox.clear()
            
            for instrumedtID in self.OrderDict:
                #添加备选项
                self.comboBox.addItem(instrumedtID)
                #订阅行情
                self.getQuote(instrumedtID)
            # print(self.OrderDict)

        # self.radioButton.se
        #信号绑定
        # self.comboBox.keyPressEvent=self.comboBox_keyPressEvent   pushButton_del
        self.comboBox.currentIndexChanged.connect(self.comboBox_keyPressEvent)
        self.pushButton.clicked.connect(self.addConditionOrder)
        self.pushButton_del.clicked.connect(self.deleteConditionOrder)
        self.signalHandle.updateGUISignal.connect(self.updateGUI)
        self.radioButton.toggled.connect(self.on_radio_button_toggled)  #多空选项选中变样式
        self.radioButton_2.toggled.connect(self.on_radio_button_toggled)
        self.pushButton_price.clicked.connect(self.price_clicked)
        #显示设置
        # self.tableWidget.setItemAlignment(Qt.AlignHCenter)
        # self.tableWidget.setItemAlignment(Qt.AlignVCenter)
        

        if self.currentID in self.OrderDict:
            self.updateTable(self.currentID)
        # for order in self.OrderList:
        #     self.TableAddOrder(order)
        if self.comboBox.currentText().strip()!='':
            self.comboBox_keyPressEvent()
    def on_radio_button_toggled(self):
        if self.radioButton.isChecked():
            self.radioButton.setStyleSheet("QRadioButton { color: green;font-size: 20px; font-weight: bold; }")
            self.radioButton_2.setStyleSheet("QRadioButton { color: red;font-size: 14px; }")
        else:
            self.radioButton_2.setStyleSheet("QRadioButton { color: red;font-size: 20px; font-weight: bold; }")
            self.radioButton.setStyleSheet("QRadioButton { color: green;font-size: 14px; }")
    def price_clicked(self):
        self.doubleSpinBox.setValue(float(self.pushButton_price.text()))
    def eventFilter(self, obj, event):
        if obj == self.comboBox and event.type() == QEvent.KeyPress:
            if event.key() == Qt.Key_Enter or event.key() ==Qt.Key_Return:
                # 在此处添加响应回车事件的代码
                # print("回车事件被触发！")
                self.comboBox_keyPressEvent()
        return super(MainWindow, self).eventFilter(obj, event)
    def InitTable(self):
        #self.tqApi.OrderList
        pass
    def comboBoxChanged(self,text):
        # print(text)
        pass
    def Join(self):
        self.CTPapi.Init()
        self.CTPapi.Join()
    def getQuote(self,instrumedtID):
        if instrumedtID in self.quoteDict:
            return self.quoteDict[instrumedtID]
        code=getCode(instrumedtID)
        try:
            exchange=self.user_info['IDtoExchange'][code]
            # self.currentID=instrumedtID
        except:
            self.statusbar.showMessage('请检查合约代码',10000)
            return
        exchange_ID=exchange+'.'+instrumedtID
        quote=self.tqApi.get_quote(exchange_ID)
        self.quoteDict[instrumedtID]=quote
        return quote
    def currentIndexChanged(self,index):
        instrumedtID=self.comboBox.itemText(index)
        self.comboBox_keyPressEvent()
    def comboBox_keyPressEvent(self):
        self.comboBox.clearFocus()
        instrumedtID=self.comboBox.currentText()
        if instrumedtID not in self.quoteDict:
            quote=self.getQuote(instrumedtID)
            time.sleep(0.5)
        else:
            quote=self.quoteDict[instrumedtID]
        self.currentID=instrumedtID
        # exchange_ID=exchange+'.'+instrumedtID
        # # self.signalHandle.getQuoteSignal.emit(exchange_ID)
        # self.tqApi.updateGUIdata['keyEnterID']=exchange_ID
        # quote=self.quoteDict[instrumedtID]
        # self.tqApi.updateGUIdata['keyEnterQuote']=quote
        for i in range(10):
            if isnan(quote.pre_settlement):
                time.sleep(0.2)
            else:
                break
        self.pushButton_price.setText(str(quote.last_price)) 
        self.doubleSpinBox.setValue(quote.pre_settlement)
        self.doubleSpinBox.setSingleStep(quote.price_tick)
        self.tableWidget.clearContents()
        self.updateTable(instrumedtID)
        # print(quote.last_price,quote.pre_settlement,quote.price_tick)
        # print(type(quote.last_price),isnan(quote.last_price))
    def addConditionOrder(self):
        '''新增条件单'''
        Direction=THOST_FTDC_D_Buy if self.radioButton_2.isChecked() else THOST_FTDC_D_Sell
        openOrder={
            'InstrumentID':self.comboBox.currentText(),
            "OpenClose":THOST_FTDC_OF_Open,
            'LongShort':Direction,
            "Volume":self.spinBox.value(),   #手数
            "triggerLogic":self.comboBox_2.currentText(),#大于小于等 < >  <=  >=
            "triggerPrice":self.doubleSpinBox.value(), #触发价
            "cutLossNum":self.spinBox_2.value(), #止损点数
            "stopProfitNum":self.spinBox_3.value(), #止盈点数
            "createtime":time.time(),
            "status":OrderStatus[0],
            "Distance":0
        }
        
        if logicalOprator(self.quoteDict[openOrder['InstrumentID']].last_price,openOrder['triggerLogic'],openOrder['triggerPrice']):
            self.statusbar.showMessage('条件已满足，请检查',10000)
            return
        
        # openOrder=OpenOrder(self.comboBox.text(),THOST_FTDC_OF_Open,Direction,self.spinBox.value(),time.time(),OrderStatus[0],self.comboBox_2.currentText(),self.doubleSpinBox.value(),self.spinBox_2.value(),self.spinBox_3.value())
        # self.signalHandle.sendOrderSignal.emit(openOrder)
        if openOrder['InstrumentID'] not in self.OrderDict:
            self.OrderDict[openOrder['InstrumentID']]=[]
            self.comboBox.addItem(openOrder['InstrumentID'])
        self.OrderDict[openOrder['InstrumentID']].append(openOrder)
        self.OrderDict[openOrder['InstrumentID']].sort(key=lambda x: x['triggerPrice'],reverse=True)
        self.updateTable(openOrder['InstrumentID'])
        with open('orderDict.json','w',encoding='utf8') as f:
            json.dump(self.OrderDict,f)
    def deleteConditionOrder(self):
        '''删除选中条件单'''
        ls=self.tableWidget.selectedItems()
        if len(ls)==0:return
        InstrumentID,stamp=ls[0].text(),ls[9].text()
        orderLs=self.OrderDict[InstrumentID]
        for order in orderLs:
            if str(order['createtime'])==stamp:
                orderLs.remove(order)
                break
        self.tableWidget.clearContents()
        with open('orderDict.json','w',encoding='utf8') as f:
            json.dump(self.OrderDict,f)
        self.updateTable(InstrumentID)
    def updateTable(self,InstrumentID):
        if InstrumentID not in self.OrderDict:
            self.statusbar.showMessage('无此品种！',10000)
            return
        while self.tableWidget.rowCount()<len(self.OrderDict[InstrumentID]):
            self.tableWidget.insertRow(0)

        for rowCount,order in enumerate(self.OrderDict[InstrumentID]):#triggerLogic
            self.tableWidget.setItem(rowCount, 0,QTableWidgetItem(order['InstrumentID']))
            self.tableWidget.setItem(rowCount,1,QTableWidgetItem(str(order['triggerLogic'])))
            self.tableWidget.setItem(rowCount,2,QTableWidgetItem(str(order['triggerPrice'])))
            if 'Distance' not in order:order['Distance']=0
            self.tableWidget.setItem(rowCount,3,QTableWidgetItem(str(order['Distance'])))
            Direction='多' if order['LongShort']==THOST_FTDC_D_Buy else "空"
            self.tableWidget.setItem(rowCount,4,QTableWidgetItem(Direction))
            OpenClose="开" if order['OpenClose']==THOST_FTDC_OF_Open else "平"
            self.tableWidget.setItem(rowCount,5,QTableWidgetItem(OpenClose))
            self.tableWidget.setItem(rowCount,6,QTableWidgetItem(str(order['cutLossNum'])))
            self.tableWidget.setItem(rowCount,7,QTableWidgetItem(str(order['stopProfitNum'])))
            self.tableWidget.setItem(rowCount,8,QTableWidgetItem(order['status']))
            self.tableWidget.setItem(rowCount,9,QTableWidgetItem(str(order['createtime'])))
           
    def updateGUI(self):
        if self.currentID in self.quoteDict:
            self.pushButton_price.setText(str(self.quoteDict[self.currentID].last_price)) 

        ###遍历所有品种
        for InstrumentID,orderLs in self.OrderDict.items():
            quote=self.quoteDict[InstrumentID]
            for order in orderLs:###某品种所有条件单
                order['Distance']=(order['triggerPrice']-quote.last_price)//quote.price_tick
                # self.tableWidget.setItem(rowCount,3,QTableWidgetItem(str(order['createtime'])))
                if logicalOprator(quote.last_price,order['triggerLogic'],order['triggerPrice']):

                    #删除已出发条件单,刷新表格
                    orderLs.remove(order)
                    with open('orderDict.json','w',encoding='utf8') as f:
                        json.dump(self.OrderDict,f)
                    if self.currentID==InstrumentID:self.updateTable(InstrumentID)
                    
                    #符合条件发出报
                    Beep(200,200)
                    self.ReqOrderInsert(InstrumentID,Direction=order['LongShort'],LimitPrice=order['triggerPrice'],volume=order['Volume'],CombOffsetFlag=order['OpenClose'])
                    print(quote.datetime[11:19],InstrumentID,quote.last_price,order['triggerLogic'],order['triggerPrice'])
                    
                    
                    
    def ReqOrderInsert(self,InstrumentID,Direction=THOST_FTDC_D_Buy,LimitPrice=0,volume=1,CombOffsetFlag=THOST_FTDC_OF_Close):
        self.orderfield.InstrumentID=InstrumentID
        self.orderfield.Direction=Direction
        self.orderfield.VolumeTotalOriginal=volume  #LimitPrice
        self.orderfield.LimitPrice=LimitPrice
        self.orderfield.ExchangeID=self.user_info['IDtoExchange'][getCode(InstrumentID)]
        self.orderfield.CombOffsetFlag=CombOffsetFlag     
        self.CTPapi.ReqOrderInsert(self.orderfield,0)
    def closeEvent(self, event):
        # 手动删除子Widget
        self.signalHandle.closeApiSignal.emit('')
        super().closeEvent(event)
if __name__=="__main__":
    signalHandle=SignalHandle()
    tqApi=TQapi(signalHandle,user_info,auth=TqAuth(user_info['userinfo']['TQ_username'],user_info['userinfo']['TQ_password']))


    app = QApplication(sys.argv)
    mWindow=MainWindow(InstrumentDict,signalHandle,user_info,tqApi,CTPapi)
    mWindow.show()
    sys.exit(app.exec())
